import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:socket_io_client/socket_io_client.dart' as socket_io;

import '../../config.dart';
import '../../model/login_model.dart';
import '../../pages/login_page.dart';
import '../store/user_store.dart';
import '../utils/global_context.dart';
import '../utils/toast.dart';
import 'socket_events.dart';
import 'socket_models/send_heartbeat_payload.dart';
import 'typed_socket_service.dart';

class SocketService {
  static final SocketService _instance = SocketService._internal();
  factory SocketService() => _instance;
  SocketService._internal();

  static const String _keyLogin = 'login_data';

  socket_io.Socket? _socket;
  late TypedSocketService typed;

  bool _initialized = false;
  bool _isDisconnecting = false;
  String? _currentToken;
  Timer? _heartbeatTimer;

  int _failedAttempts = 0;
  bool _hasShownError = false;
  final int _failThreshold = 3;

  /// 主入口：初始化 socket，登录后调用
  Future<void> init({
    String? url,
    String? token,
    bool forceRefreshToken = false,
  }) async {
    final actualToken = token ?? _getTokenFromStore();
    if (actualToken == null || actualToken.isEmpty) {
      print('❌ Token 为空，Socket 初始化跳过');
      return;
    }

    if (!forceRefreshToken &&
        _initialized &&
        actualToken == _currentToken &&
        _socket?.connected == true) {
      print('✅ Socket 已初始化，token 未变化，跳过重连');
      return;
    }

    if (_initialized || _socket != null) {
      await _safeDisconnect();
    }

    print('🚀 Socket 开始连接，新 token: $actualToken');

    _socket = socket_io.io(
      url ?? Config.baseUrl,
      socket_io.OptionBuilder()
          .setTransports(['websocket'])
          .disableAutoConnect() // ✅ 禁止自动连接
          .setReconnectionAttempts(10)
          .setReconnectionDelay(2000)
          .setTimeout(5000)
          .build(),
    );

    _socket!.auth = {'token': actualToken}; // ✅ 手动设置 token
    _socket!.connect(); // ✅ 手动 connect

    typed = TypedSocketService(_socket!);
    _currentToken = actualToken;
    _initialized = true;

    _socket!.onConnect((_) {
      print('✅ Socket connected: ${_socket!.id}');
      _startHeartbeat();
      _failedAttempts = 0;
      _hasShownError = false;
    });

    _socket!.onDisconnect((_) {
      print('❌ Socket disconnected');
      _stopHeartbeat();
    });

    _socket!.onError((err) {
      _failedAttempts++;
      print('🔥 Socket error #$_failedAttempts: $err');
      if (_failedAttempts >= _failThreshold && !_hasShownError) {
        _hasShownError = true;
        toast('请检查网络');
      }
    });

    typed.onSendError((data) => _handleForceLogout(data.content));
  }

  /// 从 SharedPreferences 提取 token
  String? _getTokenFromStore() {
    final jsonStr = Store().getString(_keyLogin);
    if (jsonStr.isEmpty) return null;
    try {
      final jsonMap = json.decode(jsonStr);
      return LoginModel.fromJson(jsonMap).token;
    } catch (_) {
      return null;
    }
  }

  void _startHeartbeat() {
    _stopHeartbeat();
    _heartbeatTimer = Timer.periodic(const Duration(seconds: 10), (_) {
      if (_socket?.connected == true) {
        final token = _getTokenFromStore();
        if (token != null && token.isNotEmpty) {
          print('💓 心跳发送');
          typed.emitSendHeartbeat(SendHeartbeatPayload(
            content: token,
            messageType: SocketEvent.sendHeartBeat.name,
          ));
        }
      }
    });
  }

  void _stopHeartbeat() {
    _heartbeatTimer?.cancel();
    _heartbeatTimer = null;
  }

  /// 安全断开（并等待释放连接资源）
  Future<void> _safeDisconnect() async {
    if (_socket != null) {
      _isDisconnecting = true;
      _stopHeartbeat();
      _socket!.dispose();
      await Future.delayed(const Duration(milliseconds: 200));
      _socket = null;
      _initialized = false;
      _currentToken = null;
      _failedAttempts = 0;
      _hasShownError = false;
      _isDisconnecting = false;
    }
  }

  bool get isConnected => _socket?.connected == true;

  /// 处理强制下线（如被顶号或 token 失效）
  Future<void> _handleForceLogout(String msg) async {
    toast(msg);
    await Future.delayed(const Duration(milliseconds: 500));
    await Store().remove(_keyLogin);
    await _safeDisconnect();
    Navigator.pushReplacement(
      globalContext!,
      MaterialPageRoute(builder: (_) => const LoginPage()),
    );
  }
}
